"""
命名规范：

PMG+控件类型+功能类型
控件类型可以是一词或者两个词。

相关设计思想来自ImagePy团队的SciWx中的normal控件
由WxPython代码翻译到PyQt5，并且对接口做出相关调整

作者：侯展意
qq:1295752786@qq.com
"""

from PyQt5.QtGui import QCloseEvent
from PyQt5.QtWidgets import QSpacerItem, QSizePolicy, QDialog
import logging

logger = logging.getLogger(__name__)
from pmgwidgets.widgets.extended import *

views_dic = {}
views_dic.update({'color_ctrl': PMGColorCtrl,
                  'eval_ctrl': PMGEvalCtrl,
                  'file_ctrl': PMGFileCtrl,
                  'keymap_ctrl': PMGKeyMapCtrl,
                  'folder_ctrl': PMGFolderCtrl,
                  'line_ctrl': PMGLineCtrl,
                  'number_ctrl': PMGNumberCtrl,
                  'password_ctrl': PMGPasswordCtrl})

views_dic.update({'editor_ctrl': PMGEditorCtrl,
                  'check_ctrl': PMGCheckCtrl,
                  'combo_ctrl': PMGComboCtrl,
                  'list_ctrl': PMGListCtrl,
                  'time_ctrl': PMGTimeCtrl,
                  'date_ctrl': PMGDateCtrl,
                  'datetime_ctrl': PMGDateTimeCtrl,
                  'numberspin_ctrl': PMGNumberSpinCtrl
                  })
views_dic.update({'timeseries_show': PMGTimeSeriesShow})


class PMGPanel(QWidget):
    widgets_dic: Dict[str, BaseExtendedWidget] = {}
    signal_settings_changed = pyqtSignal(dict)

    def __init__(self, parent=None, views: List[Tuple] = None, layout_dir: str = 'v', with_spacer: bool = True):
        super(PMGPanel, self).__init__(parent)
        self.layout_dir = layout_dir
        self.with_spacer = with_spacer
        if layout_dir == 'v':
            self.setLayout(QVBoxLayout())
        else:
            self.setLayout(QHBoxLayout())

        self.set_items(views)

    def on_settings_changed(self):
        self.signal_settings_changed.emit(self.get_value())

    def _set_items(self, views: List[Tuple[str]] = None):
        if views is None:
            return
        self.widgets_dic: Dict[str, QWidget] = {}
        self.layout().setContentsMargins(0, 0, 0, 0)
        for v in views:
            if isinstance(v[0], str):
                name = v[1]
                widget = views_dic[v[0]](self.layout_dir, *v[2:])
                if self.widgets_dic.get(name) is None:
                    self.widgets_dic[name] = widget
                self.layout().addWidget(widget)
                widget.signal_param_changed.connect(self.on_settings_changed)

            elif isinstance(v[0], (list, Tuple)):
                sub_layout = None
                if self.layout_dir == 'v':
                    sub_layout = QHBoxLayout()
                    self.layout().addLayout(sub_layout)
                else:
                    sub_layout = QVBoxLayout()
                    self.layout().addLayout(sub_layout)
                for subv in v:
                    name = subv[1]
                    widget = views_dic[subv[0]](self.layout_dir, *subv[2:])
                    if self.widgets_dic.get(name) is None:
                        self.widgets_dic[name] = widget
                    sub_layout.addWidget(widget)
                    # if self.force_spacing == True:
                    #     self.layout().addWidget(QLabel(' '))
                if self.layout_dir == 'h':
                    sub_layout.addItem(QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))
                else:
                    sub_layout.addItem(QSpacerItem(20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
        if self.with_spacer:
            self.layout().addItem(QSpacerItem(0, 0, QSizePolicy.Minimum, QSizePolicy.Expanding))

    def set_items(self, items: List[Tuple] = None):
        self.widgets_dic = {}
        for i in range(self.layout().count()):
            widget = self.layout().itemAt(i).widget()
            layout = self.layout().itemAt(i).layout()
            if widget is not None:
                widget.deleteLater()
            if layout is not None:
                for j in range(layout.count()):
                    widget = layout.itemAt(j).widget()
                    if widget is not None:
                        widget.deleteLater()
                layout.deleteLater()
        self._set_items(items)

    def get_ctrl(self, ctrl_name: str) -> 'BaseExtendedWidget':
        return self.widgets_dic.get(ctrl_name)

    def get_value(self):
        result = {}
        for k in self.widgets_dic:
            result[k] = self.widgets_dic[k].get_value()
        return result

    def set_value(self, values: Dict[str, Union[int, str, List, float, Tuple]]):
        """
        设置值。
        如果键不存在，不会报错，而是会忽略这一项。
        :param values:
        :return:
        """
        for k in values.keys():
            w = self.widgets_dic.get(k)
            # assert w is not None, 'Widget named \'%s\' is not found!' % k
            if w is not None:
                w.set_value(values[k])

    def closeEvent(self, a0: QCloseEvent) -> None:
        super().closeEvent(a0)
        self.deleteLater()
        self.signal_settings_changed.emit(self.get_value())


class PMGPanelDialog(QDialog):
    def __init__(self, parent, views, with_spacer=False):
        super().__init__(parent)
        self.panel = PMGPanel(parent=self, views=views, with_spacer=with_spacer)
        self.setLayout(QVBoxLayout())
        # self.layout().setContentsMargins(0,0,0,0)
        self.layout().addWidget(self.panel)
        button_ok = QPushButton(self.tr('Ok'))
        self.layout().addWidget(button_ok)
        button_ok.clicked.connect(self.close)


def is_standard_widget_name(widget_name: str) -> bool:
    """
    返回字符串是否对应一个标准化的PMGPanel控件。
    :return:
    """
    return views_dic.get(widget_name) is not None


def parse_simplified_pmgjson(identifier, data, params) -> Union[List[Union[int, str]], None]:
    """
    解析简化版的json数据！
    :param identifier:
    :param data:
    :param params:
    :return:
    """
    if len(params) > 0:
        if is_standard_widget_name(params[0]):
            return [params[0], identifier, 'Input Value', data] + params[1:]

    if isinstance(data, bool):
        return ['check_ctrl', identifier, 'Input Bool', data]

    elif isinstance(data, (int, float)):

        return ['numberspin_ctrl', identifier, 'Input Value', data] + params

    elif isinstance(data, str):
        return ['line_ctrl', identifier, 'Input String', data]



if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)
    # 类型；名称；显示的提示文字;初始值；//单位；范围
    views1 = [('line_ctrl', 'name', 'What\'s your name?', 'hzy'),
              ('password_ctrl', 'password', 'What\'s your password?', '123456'),
              ('file_ctrl', 'file_dir', 'File Name', '/home/hzy/Desktop/123.txt'),
              ('editor_ctrl', 'code', 'Input Python Code', 'print(123)', 'sql'),
              ('number_ctrl', 'age', 'How old are you?', 88, 'years old', (0, 150)),
              ('number_ctrl', 'height', 'How High could This Plane fly?', 12000, 'm', (10, 20000)),
              ('check_ctrl', 'sport', 'do you like sport', True),
              ('numberspin_ctrl', 'eyesight', '视力', 4.0, '度', (3.0, 5.5), 0.1),
              ('numberspin_ctrl', 'apple_num', '苹果数量', 4, '个', (0, 10), 1), ]
    views2 = [('combo_ctrl', 'plane_type', 'plane type', 'f22', ['f22', 'f18', 'j20', 'su57'],
               ['f22战斗机', 'f18战斗轰炸机', 'j20战斗机', 'su57战斗机']),
              ('color_ctrl', 'color', 'Which color do u like?', (0, 200, 0)),
              ('list_ctrl', 'inputs', 'Set Inputs', [['1', '2', '3'], ['#1', '#2', '#3']], lambda: str(123)),
              ('list_ctrl', 'inputs_2', 'Set Inputs', [[None, None, None], ['##1', '##2', '##3'], ], lambda: None),
              ('date_ctrl', 'date', '设置时间', (1970, 7, 21)),
              [
                  ('eval_ctrl', 'code_eval', 'Evaluate this code', 123 + 456, 'normal'),
                  ('eval_ctrl', 'code_eval2', 'Evaluate this code', (1, 2, 3), 'safe')
              ],
              ('keymap_ctrl', 'key_map2', 'Key For Find', 'Ctrl+F'),
              ]
    sp = PMGPanel(views=views1, layout_dir='v')
    sp.set_items(views1)
    sp.signal_settings_changed.connect(lambda settings: print('views1-settings', settings))
    sp.show()

    sp2 = PMGPanel(views=views2, layout_dir='v')
    sp2.signal_settings_changed.connect(lambda settings: print('views2-settings', settings))
    sp2.set_items(views2)
    sp2.show()

    import random

    views3 = \
        [
            ('timeseries_show', 'cpu_occupation', 'CPU占用', {'timestamps': [i + 1 for i in range(10)],
                                                            'line1': {'tag': 'CPU利用率1',
                                                                      'data': [random.randint(0, 100) for i in
                                                                               range(10)]},
                                                            'line2': {'tag': 'CPU利用率2',
                                                                      'data': [random.randint(0, 100) for i in
                                                                               range(10)]}

                                                            }, (0, 100), '时间', '占用率', 78),
        ]
    sp3 = PMGPanel(views=views3, layout_dir='v')
    sp3.signal_settings_changed.connect(lambda settings: print('views2-settings', settings))
    sp3.set_items(views3)
    sp3.show()

    val = sp.get_value()  # 返回一个字典。初始值为表格的第二列：第四列。
    print(val)
    sp.signal_settings_changed.connect(lambda x: print(x))
    sys.exit(app.exec_())
